//#pragma warning(disable:4290) // c++ exception specification

#include <stdexcept>
#include <string>
#include <iostream>
#include "CodeGenerator.h"
#include "Measurer.h"
using namespace std;
bool CodeGenerator::isLoadID = false;

CodeGenerator::CodeGenerator(SymbolTable* st, Calc* cl):pc(0),top(-1),ebp(0),esp(0){	
	mySymbolTable = st;
	myCalculator = cl;
}
void CodeGenerator::writeCode(int op){
	if(pc<MAX_CODE_MEMORY){
		code[pc++] = (char)op;
	}
}
void CodeGenerator::writeCode2(int op, int value){
	writeCode(op);
	code[pc] = char(value >> 8); 	code[pc+1] = char(value);	
	pc = pc+2;
}
void CodeGenerator::writeCode3(int op, char varname[], int value){
	var[pc] = varname;
	writeCode2(op,value);	
}
//get the op code
int  CodeGenerator::getNextInstruction(){
	return (int)code[pc++];
}
//get the number
int  CodeGenerator::getNextInstruction2(){
	int p1, p2;
	p1 = (int) code[pc];
	p2 =  (int) code[pc+1];
	pc = pc+2;
	return ((p1<<8) + p2);

}



// push variable or value to the stack
void  CodeGenerator::push(char* name){
	
		
	strcpy(&stack[++top][0],name);//, = name;
	
	
}
// pop variable or value from the stack
char*  CodeGenerator::pop() {
	//char* c = new char(256);
	//int t = top;
	/*for(int i=0; i< 256; i++){
		c[i] = stack[t][i];
	}*/
	//top--;
	//return c;
	return &stack[top--][0];
}
char* CodeGenerator::Top(){
	//char* c = new char(256);
	/*for(int i=0; i< 256;i++){
		c[i] = stack[top][i];
	}*/
	return &stack[top][0];
}

void CodeGenerator::init(){
	pc=1;
}

int CodeGenerator::next(){
	return code[pc++];
}

void CodeGenerator::MathCalculator(char* v, char* v2, int op){
	int number = 0; // temporary store for number 
	int number2 = 0; // temporary store for number 
	char t[256];

	if(isdigit(v[0]) && isdigit(v2[0])){
		 number = atoi(v);
		 number2 = atoi(v2);
			switch(op){
			case ADD:
				sprintf(t, "%d", number+number2);
				push(t);
				break;
			case SUB:
				sprintf(t, "%d", number-number2);
				push(t);
				break;
			
			case MUL:
				sprintf(t, "%d", number*number2);
				push(t);
				break;
			
			case DIVI:
				if (number2!=0){
					sprintf(t, "%d", number/number2);
					push(t);
				}
				else{
					printf("Division by zero\n");
					exit(0);
				}
				break;
			}
	}
	else{		

		//if (number==0)
		if(!isdigit(v[0]))
			Measurer::updateTmpValue(v,-1);
		else
			//Measurer::updateTmpValue(number,-1);
			Measurer::updateTmpValue(atoi(v),-1);

		//if (number2==0)
		if(!isdigit(v2[0]))
			Measurer::updateTmpValue(v2,op);
		else
			//Measurer::updateTmpValue(number2,op);		
			Measurer::updateTmpValue(atoi(v2),op);		
			
			
			sprintf(t, "%s", "TMP");
			push(t);			
			
			//push("TMP");
	}
		
	
}
void CodeGenerator::showCode(){
	Measurer_Node* node = Measurer::root;
	printf("Assembly Code:\n");
	int number = 0; // temporary store for number 
	int number2 = 0; // temporary store for number 
	string s = ""; // temporary store for variable name
	char t[256]; 
	pc = 0;
	//symbolTableObj* tmp;
	int addr  =0; // temporary store for address
	int op = 0;
	char* tmp;
	char* tmp2;
	
	for(;;){
		for(int j =0; j<256;j++){
			t[j]=0;
		}
		op  = next();
		switch(op){
			
		case LOD:
			
			cout << ASSEMBLYCODE[op] << " " ;			
			cout << var[pc-1] <<endl;						
			push(&var[pc-1][0]);
			getNextInstruction2();
			tmp = Top();
			Measurer::updateTmpValue(tmp,-1);
			CodeGenerator::isLoadID = true;	
			

			//i=i+2;
			break;
		case STO:
			cout << ASSEMBLYCODE[op] << " " ;			
			cout << var[pc-1] << endl;
					
			tmp= pop();
			getNextInstruction2();
				CodeGenerator::isLoadID = false;
			if(isdigit(tmp[0])){
				number = atoi(tmp);
				Measurer::updateTmpValue(number,-1);
			}
			else{
				Measurer::updateByTmp(var[pc-3]);
			}

			
		//	Measurer::updateByTmp(var[pc]);
		//	Measurer::updateTmpValue(number,op);
			

			break;
		case ADD:
			
			tmp2 = (pop());
			tmp = (pop());
			cout << ASSEMBLYCODE[op] << "," << tmp << "," << tmp2 << endl;			
			MathCalculator(tmp,tmp2,op);
			//myCalculator->checkingOP(ADD);
			CodeGenerator::isLoadID = false;
			break;

		case SUB:
			tmp2 = (pop());
			tmp = (pop());
			cout << ASSEMBLYCODE[op] << "," << tmp << "," << tmp2 << endl;			
			MathCalculator(tmp,tmp2,op);
			//myCalculator->checkingOP(ADD);
			CodeGenerator::isLoadID = false;
			break;
		case MUL:

			tmp2 = (pop());
			tmp = (pop());
			cout << ASSEMBLYCODE[op] << "," << tmp << "," << tmp2 << endl;			
			MathCalculator(tmp,tmp2,op);
			CodeGenerator::isLoadID = false;
			//myCalculator->checkingOP(MUL);
			break;
		case DIVI:
			tmp2 = (pop());
			tmp = (pop());
			cout << ASSEMBLYCODE[op] << "," << tmp << "," << tmp2 << endl;			
			MathCalculator(tmp,tmp2,op);
			CodeGenerator::isLoadID = false;
			break;
		case LIT:
			cout << ASSEMBLYCODE[op] << " " ;			
			number = getNextInstruction2();
			printf("%d\n",number);			
			
			sprintf(t, "%s", "TMP2");
			push(t);			
			
			//number = atoi(&stack[top][0]);
			Measurer::updateTmpValue(number,op);

			//myCalculator->pushNumber2(number);
			
			//i=i+2;
			break;
		case WRT:
			cout << ASSEMBLYCODE[op] << " " ;			
			
			tmp = pop();
			
			cout << tmp << " " <<endl;
			
			//cout << Measurer::output(tmp);
			//Measurer::output(tmp);
			printf("The entropy = %f",Measurer::measureEntropy(tmp));
			
			break;
		case TMT:
			exit(0);
			break;
		default:			
			cout << "Unexpected code : " << ASSEMBLYCODE[op];
			exit(1);			
			//break;
		}
		
		printf("\n");
		
	}
}







